package com.konka.spring.framework.context;

import com.konka.spring.framework.annotation.Autowired;
import com.konka.spring.framework.beans.BeanWrapper;
import com.konka.spring.framework.beans.config.BeanDefinition;
import com.konka.spring.framework.beans.support.BeanDefinitionReader;
import com.konka.spring.framework.beans.support.DefaultListableBeanFactory;
import com.konka.spring.framework.core.BeanFactory;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author konka
 * @date 2023/2/8
 * @description:
 */
public class ApplicationContext implements BeanFactory {

    /**
     * 缓存BeanDefinition
     */
    private DefaultListableBeanFactory registry = new DefaultListableBeanFactory();

    /**
     * 读取配置
     */
    private BeanDefinitionReader definitionReader;

    /**
     * 缓存beanName对应bean实例对象
     */
    private Map<String,Object> factoryBeanObjectCache = new ConcurrentHashMap<>();

    /**
     * 循环依赖的标识，当前正在创建的beanName
     */
    private Set<String> singletonsCurrentlyInCreation = new HashSet<>(16);
//            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    /**
     * 一级缓存
     */
    private Map<String,Object> singletonObjects = new ConcurrentHashMap<>(256);
    /**
     * 二级缓存
     */
    private Map<String,Object> earlySingletonObjects = new HashMap<>(16);
    /**
     * 三级缓存（终极缓存）（这与源码不太一致，先凑合用）
     */
    private Map<String,BeanWrapper> factoryBeanInstanceCache = new HashMap<>(16);

    public ApplicationContext(String ... configLocations) {
        definitionReader = new BeanDefinitionReader(configLocations);

        try {
            //将配置中扫描到的类，转换为BeanDefinition
            List<BeanDefinition> beanDefinitions = definitionReader.loadBeanDefinition();
            //将BeanDefinition信息存储
            registry.doRegistBeanDefinition(beanDefinitions);
            //加载非懒加载的bean
            doLoadInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载非懒加载的bean
     */
    private void doLoadInstance() {
        if (this.registry.beanDefinitionMap.isEmpty()){
            return;
        }
        for (Map.Entry<String, BeanDefinition> entry : this.registry.beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (!beanDefinition.isLazyInit()){
                getBean(beanName);
            }
        }
    }

    @Override
    public Object getBean(Class beanClazz) {
        return getBean(beanClazz.getName());
    }

    @Override
    public Object getBean(String beanName) {
        //首先获取BeanDefinition
        BeanDefinition beanDefinition = this.registry.beanDefinitionMap.get(beanName);
        Object singleton = getSingleton(beanName,beanDefinition);
        if (singleton != null){return singleton;}
        if (!singletonsCurrentlyInCreation.contains(beanName)){
            singletonsCurrentlyInCreation.add(beanName);
            //特殊处理循环依赖多例问题
            /*try {
                Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
                for (Class<?> anInterface : clazz.getInterfaces()) {
                    singletonsCurrentlyInCreation.add(anInterface.getName());
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }*/
        }
        //反射实例化对象
        Object instance = instantiateBean(beanName,beanDefinition);
        //
        this.singletonObjects.put(beanName,instance);
        //特殊处理循环依赖多例问题
       /* for (Class<?> anInterface : instance.getClass().getInterfaces()) {
            this.singletonObjects.put(anInterface.getName(),instance);
        }*/
        //将对象实例包装成BeanWrapper
        BeanWrapper beanWrapper = new BeanWrapper(instance);
        //依赖注入
        populateBean(beanName,beanDefinition,beanWrapper);
        //保存到IOC容器中
        this.factoryBeanInstanceCache.put(beanName,beanWrapper);

        return beanWrapper.getWrappedInstance();
    }

    private Object getSingleton(String beanName, BeanDefinition beanDefinition) {
        //先从一级缓存获取对象
        Object bean = singletonObjects.get(beanName);
        //如果一级缓存中没有，但是有创建标识，说明正在创建，是循环依赖
        if (bean == null && singletonsCurrentlyInCreation.contains(bean)){
            bean = earlySingletonObjects.get(beanName);
            //如果二级缓存中也没有，就尝试从三级缓存中拿
            if (bean == null){
                bean = instantiateBean(beanName,beanDefinition);
                //创建出来的对象重新放到二级缓存中
                earlySingletonObjects.put(beanName,bean);
            }
        }
        return bean;
    }

    /**
     * 填充bean（填充autowired修饰的bean）
     * @param beanName
     * @param beanDefinition
     * @param beanWrapper
     */
    private void populateBean(String beanName, BeanDefinition beanDefinition, BeanWrapper beanWrapper) {
        Object instance = beanWrapper.getWrappedInstance();

        Class<?> clazz = beanWrapper.getWrappedClass();

        for (Field field : clazz.getDeclaredFields()) {
            if (!field.isAnnotationPresent(Autowired.class)){ continue; }
            Autowired autowired = field.getAnnotation(Autowired.class);
            String autowiredBeanName = autowired.value().trim();
            if ("".equals(autowiredBeanName)){
                autowiredBeanName = field.getType().getName();
            }
            field.setAccessible(true);
            try {
                /*if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null) {
                    continue;
                }*/
                field.set(instance, getBean(autowiredBeanName));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 初始化bean
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object instantiateBean(String beanName, BeanDefinition beanDefinition) {
        String beanClassName = beanDefinition.getBeanClassName();
        Object instance = null;
        try {
            Class<?> clazz = Class.forName(beanClassName);

            instance = clazz.newInstance();

            factoryBeanObjectCache.put(beanName,instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return instance;
    }

    /**
     * 对外提供一个注册bean数量的接口，方便判断
     * @return
     */
    public int getBeanDefinitionCount(){
        return this.registry.beanDefinitionMap.size();
    }

    /**
     * 对外提供全部注册的beanName数组
     * @return
     */
    public String[] getBeanDefinitionNames(){
        return this.registry.beanDefinitionMap.keySet().toArray(new String[0]);
    }

    /**
     * 得到配置
     * @return
     */
    public Properties getConfig(){
        return this.definitionReader.getConfig();
    }


}
